

package net.seqalign;

import java.io.*;
import java.util.*;

import net.matvec.*;

public class Align {

    public static boolean printHelp = false;
    public static double temp = .1;
    public static int popSize = 100;
    public static int offspringSize = 50;
    public static int generations = 200;
    public static String penaltyMatrixFileName;
    public static Matrix penaltyMatrix;
    public static String sequenceFileName;
    public static List<String> sequences;
    public static boolean acidType;   // True = amino acid sequence; 
                                         // False = nucleic acid sequence.

    public static void main(String[] args){
	new Align().start(args);
    }

    public void start(String[] args){
	// Welcome message
	System.out.println("Evolutionary alignment tool. Version: 0.0.1");
	// Parse args
	if (!parseArgs(args)){
	    System.err.println("Error parsing args: exiting.");
	    System.exit(1);
	}
	if (printHelp) {
	    printHelp();
	    return;
	}
	printArgInfo();
	if (!loadAlgoData()){
	    System.err.println("Error loading algorithm data: exiting.");
	    System.exit(1); 
	}
	AlignmentEvolver sim = new AlignmentEvolver();
	sim.simulate();
    }

    public boolean parseArgs(String[] args){
	for (int i = 0; i < args.length; i++){
	    if (args[i].equals("--seqfile")){
		sequenceFileName = args[++i];
		continue;
	    } else if (args[i].equals("--penalty-matrix")){
		penaltyMatrixFileName = args[++i];
		continue;
	    } else if (args[i].equals("--generations")){
		generations = Integer.parseInt(args[++i]);
		continue;
	    } else if (args[i].equals("--temp")){
		temp = Double.parseDouble(args[++i]);
		continue;
	    } else if (args[i].equals("--pop-size")){
		popSize = Integer.parseInt(args[++i]);
		continue;
	    } else if (args[i].equals("--offspring-size")){
		offspringSize = Integer.parseInt(args[++i]);
		continue;
	    } else if (args[i].equals("--acid-type")){
		if (args[i+1].equals("nucleic")) acidType = false;
		else if (args[i+1].equals("amino")) acidType = true;
		else {
		    System.err.println("Unknown acid type: " + args[i+1]);
		    return false;
		}
		i++;
		continue;
	    } else if (args[i].equals("--help")){
		printHelp = true;
	    } else {
		System.err.println("Unknown parameter: " + args[i]);
		return false;
	    }
	}
	return true;
    }

    public void printArgInfo(){
	System.out.println(" #");
	System.out.println(" # Algorithm running parameters:");
	System.out.println(" #   Generations:     " + generations);
	System.out.println(" #   Population Size: " + popSize);
	System.out.println(" #   Offspring Size:  " + offspringSize);
	System.out.println(" #   Temperature:     " + temp);
	System.out.println(" #   Acid type:       " +
			   (acidType ? "Amino acid" : "Nucleic Acid"));
	System.out.println(" #   Penalty Matrix:  " + penaltyMatrixFileName);
	System.out.println(" #   Sequence File:   " + sequenceFileName);
    }

    public boolean loadAlgoData(){
	// First load the matrix.
	try {
	    if (penaltyMatrixFileName == null){
		System.err.println("You must specifiy a penalty matrix.");
		return false;
	    } else if (penaltyMatrixFileName.equals("")){
		System.err.println("Penalty matrix file not existant.");
		return false;
	    }
	    penaltyMatrix = Matrix.readMatrix(penaltyMatrixFileName);
	    if (!checkMatrix(penaltyMatrix))	return false;
	} catch (MatrixIOException e){
	    System.err.println("Error reading matrix:");
	    e.printStackTrace();
	    return false;
	}
	try {
	    File f = new File(sequenceFileName);
	    BufferedReader br = new BufferedReader(
				new InputStreamReader(
				new FileInputStream(f)));
	    sequences = new ArrayList<String>();
	    String str;
	    while ((str = br.readLine()) != null){
		sequences.add(str);
	    }
	    br.close();
	    if (sequences.size() < 2){
		System.err.println("There were not enough sequences" +
				   " in your seq file.");
		return false;
	    }
	} catch (IOException e){
	    System.err.println("Error reading alignment sequences.");
	    return false;
	}
	return true;
    }

    private boolean checkMatrix(Matrix m){
	if (acidType){ // We are an amino acid substitution matrix
	    if (m.getRows() != 22 || m.getColumns() != 22){
		System.err.println("The amino acid sub matrix is not 22x22.");
		return false;
	    }
	} else {       // We are a nucleic acid substitution matrix
	    if (m.getRows() != 8 || m.getColumns() != 8) {
		System.err.println("The nucleic acid sub matric is not 7x7.");
		return false;
	    }
	}
	return true;
    }

    public void printHelp(){
	System.out.println("Brief help:");
	System.out.println("  seqalign --seqfile FILE " + 
			   "--penalty-matrix MTX_FILE [PARAMETERS]");
	System.out.println("  Recognized parameters:");
	System.out.println("    --seqfile FILE");
	System.out.println("    --penalty-matrix MTX_FILE");
	System.out.println("    --acid-type <nucleic|amino>");
	System.out.println("    --generations NUM");
	System.out.println("    --temp DOUBLE");
	System.out.println("    --pop-size NUM");
	System.out.println("    --offspring-size NUM");
	System.out.println("    --help");
	System.out.println("  Where FILE and MTX_FILE are files and NUM is a");
	System.out.println("  integer and DOUBLE is a double precision");
	System.out.println("  floating point number.");
    }

}
